import 'package:erp/res/resources.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

export 'field/filter_chip.dart';
export 'field/radio.dart';
export 'field/selector.dart';
export 'field/text_field.dart';

class FormBuilder extends StatefulWidget {
  final FormManagement formManagement;
  final List<Widget> children;
  final Map<String, dynamic>? _initStateMap;
  final Map<String, dynamic>? initialValue;

  FormBuilder({
    bool readOnly = false,
    required this.formManagement,
    required this.children,
    this.initialValue,
  }) : this._initStateMap = {'readOnly': readOnly};

  @override
  State<StatefulWidget> createState() => _FormBuilderState();
}

class _FormData extends InheritedWidget {
  final _ResourceManagement data;

  final Map<String, dynamic>? initStateMap;
  final Map<String, dynamic>? initialValue;

  _FormData(
    this.data, {
    required Widget child,
    this.initStateMap,
    this.initialValue,
  }) : super(child: child);

  @override
  bool updateShouldNotify(covariant _FormData oldWidget) {
    return true;
  }

  static _FormData of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<_FormData>()!;
  }
}

class _FormBuilderState extends State<FormBuilder> {
  late final _ResourceManagement resourceManagement;

  _FormBuilderState();

  @override
  void initState() {
    super.initState();
    resourceManagement = widget.formManagement._resourceManagement;
  }

  @override
  void dispose() {
    super.dispose();
    resourceManagement.valueField.clear();
    resourceManagement.keys.clear();
  }

  @override
  Widget build(BuildContext context) {
    return _FormData(
      resourceManagement,
      initialValue: widget.initialValue,
      initStateMap: widget._initStateMap,
      child: Column(
        children: widget.children,
      ),
    );
  }
}

class ValidateResult {
  final bool result;
  final String? message;
  final GlobalKey? globalKey;

  ValidateResult({
    required this.result,
    this.message,
    this.globalKey,
  });

  ValidateResult.ok({
    this.result = true,
    this.message,
    this.globalKey,
  });

  ValidateResult.error({
    this.result = false,
    required this.message,
    required this.globalKey,
  });
}

class FormManagement {
  final _ResourceManagement _resourceManagement;

  FormManagement() : this._resourceManagement = _ResourceManagement();

  FormManagement._(this._resourceManagement);

  static FormManagement of(BuildContext context) => FormManagement._(_ResourceManagement.of(context));

  Map<String, dynamic> get data {
    Map<String, dynamic> map = {};
    _resourceManagement.valueField.forEach((key, element) {
      dynamic value = element.value;
      map[key] = value;
    });
    return map;
  }

  ValidateResult validate() {
    var name = "";
    for (var entry in _resourceManagement.valueField.entries) {
      name = entry.key;
      var element = entry.value;
      var _validator = element.widget.validator;
      if (_validator != null) {
        String? result = _validator(element.value);
        if (result != null && result.isNotEmpty) {
          return ValidateResult.error(message: result, globalKey: _resourceManagement.keys[name]);
        }
      }
    }
    return ValidateResult.ok();
  }
}

class _ResourceManagement {
  final Map<String, GlobalKey> keys = {};
  final Map<String, BaseFormFieldState> valueField = {};

  static _ResourceManagement of(BuildContext context) {
    return _FormData.of(context).data;
  }

  static Map<String, dynamic>? initStateMap(BuildContext context) {
    return _FormData.of(context).initStateMap;
  }

  static Map<String, dynamic>? initialValue(BuildContext context) {
    return _FormData.of(context).initialValue;
  }

  GlobalKey registerGlobalKey(String name) {
    return keys.putIfAbsent(name, () => GlobalKey());
  }

  void registerField(String name, BaseFormFieldState baseFormFieldState) {
    valueField[name] = baseFormFieldState;
  }
}

abstract class BaseFormField<T extends BaseFormFieldState> extends StatefulWidget {
  final String name;
  final String? label;
  final String? Function(dynamic value)? validator;
  final T? initialValue;
  final LabelPosition labelPosition;

  BaseFormField({
    required this.name,
    this.label,
    this.validator,
    this.initialValue,
    this.labelPosition = LabelPosition.left,
  });

  @override
  T createState();
}

abstract class BaseFormFieldState<T> extends State<BaseFormField> with AbstractFieldState<BaseFormField> {
  late T value;

  @override
  void initFormManagement() {
    super.initFormManagement();
    _resourceManagement.registerField(widget.name, this);
  }

  @override
  void dispose() {
    // _resourceManagement.valueField.clear();
    // _resourceManagement.keys.clear();
    super.dispose();
  }
}

mixin AbstractFieldState<T extends StatefulWidget> on State<T> {
  bool _init = false;
  late final _ResourceManagement _resourceManagement;
  late final Map<String, dynamic>? _initStateMap;
  late final Map<String, dynamic>? _initValueMap;

  late final GlobalKey key;

  String get name => (widget as BaseFormField).name;

  Map<String, dynamic>? get initStateMap => _initStateMap;

  Map<String, dynamic>? get initValueMap => _initValueMap;

  @protected
  void didChangeDependencies() {
    super.didChangeDependencies();
    if (_init) return;
    _init = true;
    _resourceManagement = _ResourceManagement.of(context);
    _initStateMap = _ResourceManagement.initStateMap(context);
    _initValueMap = _ResourceManagement.initialValue(context);
    if (name.isNotEmpty) {
      key = _resourceManagement.registerGlobalKey(name);
      initFormManagement();
    }
  }

  @protected
  @mustCallSuper
  void initFormManagement() {}

  Widget labelWrapper({required Widget child}) {
    String _label = (widget as BaseFormField).label ?? '';
    LabelPosition labelPosition = (widget as BaseFormField).labelPosition;

    Map map = _ResourceManagement.initStateMap(context) ?? {};

    return LabelWrapper(
      child: child,
      label: _label,
      labelPosition: labelPosition,
      readOnly: map['readOnly'],
    );
  }
}

enum LabelPosition { left, top }

class LabelWrapper extends StatelessWidget {
  final Widget child;
  final LabelPosition labelPosition;
  final String label;
  final bool readOnly;

  LabelWrapper({
    required this.child,
    this.label = '',
    this.labelPosition = LabelPosition.left,
    this.readOnly = false,
  });

  @override
  Widget build(BuildContext context) {
    var _label;

    RegExp exp = new RegExp(r"^(\*)(.*)");
    Iterable<RegExpMatch> matches = exp.allMatches(label);
    if (matches.length > 0) {
      if (!readOnly) {
        _label = RichText(
          text: TextSpan(
            text: matches.elementAt(0).group(1),
            style: Styles.genNormalTextStyle(color: Color(0xFFFF0000)),
            children: [
              TextSpan(
                text: matches.elementAt(0).group(2),
                style: Styles.genNormalTextStyle(),
              ),
            ],
          ),
        );
      } else {
        _label = Text(
          matches.elementAt(0).group(2)!.trim(),
          style: Styles.genNormalTextStyle(),
        );
      }
    } else {
      _label = Text(
        label,
        style: Styles.genNormalTextStyle(),
      );
    }

    var filed = labelPosition == LabelPosition.top
        ? Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              SizedBox(height: 20.h),
              _label,
              SizedBox(height: 22.h),
              child,
            ],
          )
        : Row(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              _label,
              Flexible(child: child),
            ],
          );
    return GestureDetector(
      onTap: () {
        FocusScope.of(context).requestFocus(FocusNode());
      },
      child: filed,
    );
  }
}
